home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / vbcc / pasm / output_elf.c < prev    next >
C/C++ Source or Header  |  1998-06-24  |  14KB  |  450 lines

  1. /* $VER: pasm output_elf.c V0.5 (12.10.97)
  2.  *
  3.  * This file is part of pasm, a portable PowerPC assembler.
  4.  * Copyright (c) 1997  Frank Wille
  5.  *
  6.  * pasm is freeware and part of the portable and retargetable ANSI C
  7.  * compiler vbcc, copyright (c) 1995-97 by Volker Barthelmann.
  8.  * pasm may be freely redistributed as long as no modifications are
  9.  * made and nothing is charged for it. Non-commercial usage is allowed
  10.  * without any restrictions.
  11.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  12.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  13.  *
  14.  *
  15.  * v0.5 (12.10.97) phx
  16.  *      Removed "pasm V0.x" from .comment section.
  17.  * v0.3 (10.04.97) phx
  18.  *      Fixed enforcer-hit, when external references are present.
  19.  *      Some vbcc-specific changes.
  20.  *      Support for little endian architectures.
  21.  * v0.2 (25.03.97) phx
  22.  *      Writes ELF object for 32-bit PowerPC big-endian. Either absolute
  23.  *      or ELF output format may be selected. ELF is default for all
  24.  *      currently supported platforms. PPCasm supports nine different
  25.  *      relocation types (there are much more...).
  26.  *      Compiles and works also under NetBSD/amiga (68k).
  27.  *      Changed function declaration to 'new style' in all sources
  28.  *      (to avoid problems with '...' for example).
  29.  *      File created.
  30.  */
  31.  
  32.  
  33. #define OUTPUT_ELF_C
  34. #include "ppcasm.h"
  35. #include "elf.h"
  36. #include <time.h>
  37.  
  38.  
  39. struct StrTabList {
  40.   struct list l;
  41.   uint32 index;
  42. };
  43.  
  44. struct StrTabNode {
  45.   struct node n;
  46.   char *str;
  47. };
  48.  
  49. struct ShdrNode {
  50.   struct node n;
  51.   struct Elf32_Shdr s;
  52. };
  53.  
  54. struct SymbolNode {
  55.   struct node n;
  56.   char *name;
  57.   struct Elf32_Sym s;
  58. };
  59.  
  60. struct RelaNode {
  61.   struct node n;
  62.   struct Elf32_Rela r;
  63. };
  64.  
  65.  
  66. static struct Elf32_Ehdr elf_header = {
  67.   { 0x7f,'E','L','F',ELFCLASS32,0,EV_CURRENT,0,0,0,0,0,0,0,0,0 },
  68.   ECH(ET_REL),ECH(EM_POWERPC),ECW(EV_CURRENT),0,0,0,0,
  69.   ECH(sizeof(struct Elf32_Ehdr)),
  70.   0,0,ECH(sizeof(struct Elf32_Shdr)),0,0
  71. };
  72. static char *output_name;
  73.  
  74.  
  75. void output_elf32msb(struct GlobalVars *);
  76.  
  77. static struct ShdrNode *addShdr(struct list *);
  78. static struct SymbolNode *addSymbol(struct list *,struct StrTabList *,char *);
  79. static uint32 addString(struct StrTabList *,char *);
  80. static void addRela(struct list *,uint32,uint32,uint32);
  81. static void fw(FILE *,void *,size_t);
  82.  
  83.  
  84.  
  85. void output_elf32msb(struct GlobalVars *gv)
  86. {
  87.   struct list shdrlist,symlist,relalist;
  88.   struct StrTabList shstrlist,strlist;
  89.   struct ShdrNode *shn;
  90.   struct SymbolNode *sym;
  91.   uint32 symtabidx,strtabidx,shstrtabidx,firstglobal,align1,align2;
  92.   uint32 roffset=0,soffset=sizeof(struct Elf32_Ehdr);
  93.   uint32 shdrindex=0,symindex=0;
  94.   struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
  95.   struct Symbol *symchain;
  96.   int i;
  97.   FILE *fp;
  98.  
  99.   /* init */
  100.   output_name = gv->dest_name;
  101.   elf_header.e_ident[EI_DATA] = ELFDATA2MSB;
  102.   initlist(&shdrlist);
  103.   initlist(&symlist);
  104.   initlist(&relalist);
  105.   shstrlist.index = strlist.index = 0;
  106.   initlist(&shstrlist.l);
  107.   initlist(&strlist.l);
  108.   addString(&shstrlist,"");  /* first string is always "" */
  109.   symtabidx = addString(&shstrlist,".symtab");
  110.   strtabidx = addString(&shstrlist,".strtab");
  111.   shstrtabidx = addString(&shstrlist,".shstrtab");
  112.   addShdr(&shdrlist);  /* first Shdr is always zero */
  113.   addString(&strlist,"");
  114.   addSymbol(&symlist,NULL,NULL);  /* first symbol table entry always empty */
  115.  
  116.   /* source file name symbol */
  117.   if (gv->file) {
  118.     ++symindex;
  119.     sym = addSymbol(&symlist,&strlist,gv->file);
  120.     sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_FILE);
  121.     sym->s.st_shndx = ECH(SHN_ABS);
  122.   }
  123.  
  124.   /* generate section headers for program sections */
  125.   while (nextsec = (struct Section *)sec->n.next) {
  126.     if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
  127.       sec->index = ++shdrindex;
  128.       shn = addShdr(&shdrlist);
  129.       shn->s.sh_name = ECVW(addString(&shstrlist,sec->name));
  130.       if (sec->type==ST_UDATA || (sec->flags&SF_UNINITIALIZED))
  131.         shn->s.sh_type = ECW(SHT_NOBITS);
  132.       else
  133.         shn->s.sh_type = ECW(SHT_PROGBITS);
  134.       shn->s.sh_flags = ECW(SHF_ALLOC);
  135.       if (sec->protection & SP_WRITE)
  136.         shn->s.sh_flags |= ECW(SHF_WRITE);
  137.       if (sec->protection & SP_EXEC)
  138.         shn->s.sh_flags |= ECW(SHF_EXECINSTR);
  139.       shn->s.sh_offset = ECVW(soffset);
  140.       shn->s.sh_size = ECVW(sec->size);
  141.       if (shn->s.sh_type == ECW(SHT_PROGBITS))
  142.         soffset += sec->size;
  143.       shn->s.sh_addralign = ECVW(1<<(uint32)sec->alignment);
  144.       /* add section symbol */
  145.       sym = addSymbol(&symlist,NULL,NULL);
  146.       sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_SECTION);
  147.       sym->s.st_shndx = ECVH((uint16)shdrindex);
  148.       ++symindex;
  149.     }
  150.     sec = nextsec;
  151.   }
  152.  
  153.   /* comment section */
  154.   if (gv->ident || gv->vc) {
  155.     ++shdrindex;
  156.     shn = addShdr(&shdrlist);
  157.     shn->s.sh_name = ECVW(addString(&shstrlist,".comment"));
  158.     shn->s.sh_type = ECW(SHT_PROGBITS);
  159.     shn->s.sh_offset = ECVW(soffset);
  160.     shn->s.sh_size = 1;  /* zero-byte */
  161.     if (gv->ident)
  162.       shn->s.sh_size += (uint32)strlen(gv->ident)+1;
  163.     if (gv->vc)
  164.       shn->s.sh_size += 12;
  165.     soffset += shn->s.sh_size;
  166. #ifdef LITTLEENDIAN
  167.     shn->s.sh_size = l2bw(shn->s.sh_size);
  168. #endif
  169.     shn->s.sh_addralign = ECW(1);
  170.     /* add section symbol */
  171.     sym = addSymbol(&symlist,NULL,NULL);
  172.     sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,STT_SECTION);
  173.     sym->s.st_shndx = ECVH((uint16)shdrindex);
  174.     ++symindex;
  175.   }
  176.  
  177.   /* build symbol table */
  178.   for (i=0; i<SYMHTABSIZE; i++) {  /* first, symbols with local binding */
  179.     symchain = gv->symbols[i];
  180.     while (symchain) {
  181.       if (*(symchain->name) != '.') {  /* '.symbols' are ignored */
  182.         if (symchain->type==SYM_ABS || symchain->type==SYM_RELOC) {
  183.           if (symchain->bind == SYMB_LOCAL) {
  184.             ++symindex;
  185.             sym = addSymbol(&symlist,&strlist,symchain->name);
  186.             sym->s.st_value = ECVW(symchain->value);
  187.             sym->s.st_size = ECVW(symchain->size);
  188.             sym->s.st_info = ELF32_ST_INFO(STB_LOCAL,symchain->type);
  189.             if (symchain->type == SYM_ABS)
  190.               sym->s.st_shndx = ECH(SHN_ABS);
  191.             else
  192.               sym->s.st_shndx = ECVH((uint16)symchain->relsect->index);
  193.           }
  194.         }
  195.       }
  196.       symchain = symchain->hash_chain;
  197.     }
  198.   }
  199.   firstglobal = symindex + 1;
  200.   for (i=0; i<SYMHTABSIZE; i++) {  /* then, global and weak symbols */
  201.     symchain = gv->symbols[i];
  202.     while (symchain) {
  203.       if (*(symchain->name) != '.') {  /* '.symbols' are ignored */
  204.         if (symchain->type==SYM_ABS || symchain->type==SYM_RELOC) {
  205.           if (symchain->bind > SYMB_LOCAL) {
  206.             ++symindex;
  207.             sym = addSymbol(&symlist,&strlist,symchain->name);
  208.             sym->s.st_value = ECVW(symchain->value);
  209.             sym->s.st_size = ECVW(symchain->size);
  210.             sym->s.st_info = ELF32_ST_INFO(symchain->bind,symchain->type);
  211.             if (symchain->type == SYM_ABS)
  212.               sym->s.st_shndx = ECH(SHN_ABS);
  213.             else
  214.               sym->s.st_shndx = ECVH((uint16)symchain->relsect->index);
  215.           }
  216.         }
  217.       }
  218.       symchain = symchain->hash_chain;
  219.     }
  220.   }
  221.  
  222.   /* ".rela.xxx" relocation sections */
  223.   sec = (struct Section *)gv->sectionlist.first;
  224.   while (nextsec = (struct Section *)sec->n.next) {
  225.     if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
  226.       struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
  227.       struct XReference *nextxref;
  228.       struct XReference *xref=(struct XReference *)sec->xreflist.first;
  229.       uint32 ro=roffset;
  230.       char *sptr;
  231.  
  232.       while (nextrel = (struct Reloc *)rel->n.next) {
  233.         addRela(&relalist,rel->offset,rel->addend,
  234.                 ELF32_R_INFO(rel->relocsect->index,rel->type));
  235.         roffset += sizeof(struct Elf32_Rela);
  236.         rel = nextrel;
  237.       }
  238.  
  239.       while (nextxref = (struct XReference *)xref->n.next) {
  240.         struct SymbolNode *nextsym;
  241.         char *xname = xref->xsymbol->name;
  242.         uint32 sidx=0;
  243.  
  244.         /* check if referenced symbol is already in symbol table */
  245.         sym = (struct SymbolNode *)symlist.first;
  246.         while (nextsym = (struct SymbolNode *)sym->n.next) {
  247.           if (sym->name)
  248.             if (!strcmp(xname,sym->name))
  249.               break;
  250.           ++sidx;
  251.           sym = nextsym;
  252.         }
  253.         if (nextsym==NULL) {
  254.           sidx = ++symindex;
  255.           sym = addSymbol(&symlist,&strlist,xname);
  256.           sym->s.st_info = ELF32_ST_INFO(STB_GLOBAL,STT_NOTYPE);
  257.         }
  258.         addRela(&relalist,xref->offset,xref->addend,
  259.                 ELF32_R_INFO(sidx,xref->type));
  260.         roffset += sizeof(struct Elf32_Rela);
  261.         xref = nextxref;
  262.       }
  263.  
  264.       if (ro != roffset) {  /* were there any relocations? */
  265.         sptr = (char *)alloc(strlen(sec->name) + 5);
  266.         sprintf(sptr,".rela%s",sec->name);
  267.         ++shdrindex;
  268.         shn = addShdr(&shdrlist);
  269.         shn->s.sh_name = ECVW(addString(&shstrlist,sptr));
  270.         shn->s.sh_type = ECW(SHT_RELA);
  271.         shn->s.sh_offset = ro;  /* relative offset, corrected later */
  272.         shn->s.sh_size = ECVW(roffset - ro);
  273.         /* sh_link will be set later, when .symtab exists */
  274.         shn->s.sh_info = ECVW(sec->index); /* shdr idx to which reloc applies */
  275.         shn->s.sh_addralign = ECW(4);
  276.         shn->s.sh_entsize = ECW(sizeof(struct Elf32_Rela));
  277.       }
  278.     }
  279.     sec = nextsec;
  280.   }
  281.  
  282.   /* ".shstrtab" section header string table */
  283.   ++shdrindex;
  284.   shn = addShdr(&shdrlist);
  285.   shn->s.sh_name = ECVW(shstrtabidx);
  286.   shn->s.sh_type = ECW(SHT_STRTAB);
  287.   shn->s.sh_offset = ECVW(soffset);
  288.   shn->s.sh_size = ECVW(shstrlist.index);
  289.   shn->s.sh_addralign = ECW(1);
  290.   soffset += shstrlist.index;
  291.   align1 = ((soffset + 3) & ~3) - soffset;
  292.   soffset += align1;
  293.  
  294.   elf_header.e_shoff = ECVW(soffset);
  295.   soffset += (shdrindex+3)*sizeof(struct Elf32_Shdr);
  296.   elf_header.e_shstrndx = ECVH((uint16)shdrindex);
  297.   elf_header.e_shnum = ECVH((uint16)shdrindex+3);
  298.  
  299.   /* ".symtab" symbol table */
  300.   ++shdrindex;
  301.   ++symindex;  /* number of symbol in symbol table */
  302.   shn = addShdr(&shdrlist);
  303.   shn->s.sh_name = ECVW(symtabidx);
  304.   shn->s.sh_type = ECW(SHT_SYMTAB);
  305.   shn->s.sh_offset = ECVW(soffset);
  306.   shn->s.sh_size = symindex*sizeof(struct Elf32_Sym);
  307.   shn->s.sh_link = ECVW(shdrindex+1);  /* associated .strtab section */
  308.   shn->s.sh_info = ECVW(firstglobal);  /* first non-local symbol index */
  309.   shn->s.sh_addralign = ECW(4);
  310.   shn->s.sh_entsize = ECW(sizeof(struct Elf32_Sym));
  311.   soffset += shn->s.sh_size;
  312. #ifdef LITTLEENDIAN
  313.   shn->s.sh_size = l2bw(shn->s.sh_size);
  314. #endif
  315.  
  316.   /* ".strtab" string table */
  317.   shn = addShdr(&shdrlist);
  318.   shn->s.sh_name = ECVW(strtabidx);
  319.   shn->s.sh_type = ECW(SHT_STRTAB);
  320.   shn->s.sh_offset = ECVW(soffset);
  321.   shn->s.sh_size = ECVW(strlist.index);
  322.   shn->s.sh_addralign = ECW(1);
  323.   soffset += strlist.index;
  324.   align2 = ((soffset + 3) & ~3) - soffset;
  325.   soffset += align2;  /* offset for first Rela-entry */
  326.  
  327.   /* create output file */
  328.   if (fp = fopen(output_name,"w")) {
  329.     struct StrTabNode *stn;
  330.     struct RelaNode *rn;
  331.  
  332.     fw(fp,&elf_header,sizeof(struct Elf32_Ehdr));  /* write header */
  333.  
  334.     /* write initialized section contents */
  335.     sec = (struct Section *)gv->sectionlist.first;
  336.     while (nextsec = (struct Section *)sec->n.next) {
  337.       if (!(sec->flags & (SF_DISCARD|SF_UNINITIALIZED)))
  338.         fw(fp,sec->contents,sec->size);
  339.       sec = nextsec;
  340.     }
  341.  
  342.     /* write comment section */
  343.     if (gv->ident || gv->vc) {
  344.       fw(fp,gv->alignment_bytes,1);  /* write leading 0-byte */
  345.       if (gv->ident)
  346.         fw(fp,gv->ident,strlen(gv->ident)+1);
  347.       if (gv->vc) {
  348.         uint32 v = ECW(0x16020303);
  349.  
  350.         fw(fp,&v,4);
  351.         v = ECVW((uint32)time(NULL));
  352.         fw(fp,&v,4);
  353.         v = ECW(0x03030216);
  354.         fw(fp,&v,4);
  355.       }
  356.     }
  357.  
  358.     /* write .shstrtab string table */
  359.     while (stn = (struct StrTabNode *)remhead(&shstrlist.l))
  360.       fw(fp,stn->str,strlen(stn->str)+1);
  361.  
  362.     /* write section headers */
  363.     fw(fp,gv->alignment_bytes,align1);
  364.     while (shn = (struct ShdrNode *)remhead(&shdrlist)) {
  365.       if (shn->s.sh_type == SHT_RELA) {
  366.         shn->s.sh_offset += soffset;  /* set correct offset */
  367. #ifdef LITTLEENDIAN
  368.         shn->s.sh_offset = l2bw(shn->s.sh_offset);
  369. #endif
  370.         shn->s.sh_link = ECVW(shdrindex); /* index of associated symbol table */
  371.       }
  372.       fw(fp,&(shn->s),sizeof(struct Elf32_Shdr));
  373.     }
  374.  
  375.     /* write symbol table */
  376.     while (sym = (struct SymbolNode *)remhead(&symlist))
  377.       fw(fp,&(sym->s),sizeof(struct Elf32_Sym));
  378.  
  379.     /* write .strtab string table */
  380.     while (stn = (struct StrTabNode *)remhead(&strlist.l))
  381.       fw(fp,stn->str,strlen(stn->str)+1);
  382.  
  383.     /* write relocations */
  384.     fw(fp,gv->alignment_bytes,align2);
  385.     while (rn = (struct RelaNode *)remhead(&relalist))
  386.       fw(fp,&(rn->r),sizeof(struct Elf32_Rela));
  387.  
  388.     fclose(fp);
  389.   }
  390.   else
  391.     error(25,output_name);  /* unable to create output file */
  392. }
  393.  
  394.  
  395. static struct ShdrNode *addShdr(struct list *l)
  396. {
  397.   struct ShdrNode *s = alloczero(sizeof(struct ShdrNode));
  398.  
  399.   addtail(l,&(s->n));
  400.   return (s);
  401. }
  402.  
  403.  
  404. static struct SymbolNode *addSymbol(struct list *l,struct StrTabList *sl,
  405.                                     char *name)
  406. {
  407.   struct SymbolNode *sn = alloczero(sizeof(struct SymbolNode));
  408.  
  409.   addtail(l,&(sn->n));
  410.   if (name) {
  411.     sn->name = name;
  412.     sn->s.st_name = ECVW(addString(sl,name));
  413.   }
  414.   return (sn);
  415. }
  416.  
  417.  
  418. static uint32 addString(struct StrTabList *sl,char *s)
  419. {
  420.   struct StrTabNode *sn = alloc(sizeof(struct StrTabNode));
  421.   uint32 idx = sl->index;
  422.  
  423.   sn->str = s;
  424.   addtail(&(sl->l),&(sn->n));
  425.   sl->index += (uint32)strlen(s) + 1;
  426.   return (idx);
  427. }
  428.  
  429.  
  430. static void addRela(struct list *l,uint32 o,uint32 a,uint32 i)
  431. {
  432.   struct RelaNode *rn = alloc(sizeof(struct RelaNode));
  433.  
  434.   rn->r.r_offset = ECVW(o);
  435.   rn->r.r_addend = ECVW(a);
  436.   rn->r.r_info = ECVW(i);
  437.   addtail(l,&(rn->n));
  438. }
  439.  
  440.  
  441. static void fw(FILE *fp,void *buf,size_t len)
  442. {
  443.   if (len) {
  444.     if (!fwrite(buf,1,len,fp)) {
  445.       fclose(fp);
  446.       error(26,output_name);  /* write error */
  447.     }
  448.   }
  449. }
  450.